package org.l.mybatis.core.sqlsource;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.Configuration;
import org.l.mybatis.core.annotation.SqlsourceUpdate;
import org.l.mybatis.core.exception.MethodDefineException;
import org.l.mybatis.core.exception.SqlsourceBuilderException;
import org.l.mybatis.core.handler.FieldHandler;
import org.l.mybatis.core.handler.ObjectHandler;

/**
 * Created by 严秋旺 on 2017/7/30.
 */
public class SqlsourceBuilderUpdate extends SqlsourceBuilderAbstract implements SqlsourceBuilder {
    private final SqlCommandType sqlCommandType = SqlCommandType.UPDATE;
    private SqlsourceUpdate sqlsourceUpdate;

    public SqlsourceBuilderUpdate(Configuration configuration, Class<?> type, Method method,
            SqlsourceUpdate sqlsourceUpdate) throws MethodDefineException {
        super(configuration, type, method);
        this.sqlsourceUpdate = sqlsourceUpdate;
        analysis();
    }

    private void analysis() throws MethodDefineException {
        Class<?>[] paramTypes = this.method.getParameterTypes();
        this.paramCount = paramTypes.length;

        if (paramCount == 0) {
            throw new MethodDefineException("缺少表映射对象参数:" + method);
        } else if (paramCount == 1) {
        } else {
            throw new MethodDefineException("只能接受一个表映射对象参数:" + method);
        }

    }

    @Override
    public SqlCommandType getSqlCommandType() {
        return sqlCommandType;
    }

    @Override
    public BoundSql getBoundSql(Object parameterObject) {
        List<ParameterMapping> parameterMappings = new ArrayList<>();
        String sql = createSql(parameterObject, parameterMappings);
        BoundSql boundSql = new BoundSql(this.configuration, sql, parameterMappings, parameterObject);
        return boundSql;
    }

    private String createSql(Object parameterObject, List<ParameterMapping> parameterMappings) {
        MetaObject metaObject = SystemMetaObject.forObject(parameterObject);
        Class<?> paramType = metaObject.getOriginalObject().getClass();
        ObjectHandler objectHandler = ObjectHandler.create(paramType);

        StringBuilder update = new StringBuilder(10);
        update.append("update ").append(objectHandler.getTableName()).append(" set ");
        List<FieldHandler> fieldHandlers;
        
        if(this.sqlsourceUpdate.fields().length > 0) {
            fieldHandlers = fieldHandles(objectHandler, this.sqlsourceUpdate.fields());
        }else {
            fieldHandlers = objectHandler.getDbFields();
        }
        
        int i = 0;

        for (FieldHandler handler : fieldHandlers) {
            Object value = metaObject.getValue(handler.getName());

            if (value == null)
                continue;

            if (i > 0)
                update.append(",");

            i++;
            update.append(handler.getDbName()).append(" = ? ");
            parameterMappings.add(createParameterMapping(handler));
        }

        int size = parameterMappings.size();
        String where = createWhere(null, parameterMappings, metaObject, objectHandler.getPrimaryFields());

        if (parameterMappings.size() > size || sqlsourceUpdate.force()) {
            return update + where;
        } else {
            throw new SqlsourceBuilderException(
                    "sql语句执行终止，因为没有update条件，即将执行全表update，如果要强制执行请设置@SqlsourceUpdate的force为true");
        }
    }
}
